#ifndef MEI_H
#define MEI_H
#include <boost/multi_array.hpp>
#include <iostream>
#include <string>
#include <fstream>
#include <ctime>
#include <boost/timer.hpp>
#include "MEI.h"

//Ellpack_Itpack


using namespace boost;
using namespace std;

template <typename T>
class MEI
{
	private :
	//attributs
	boost::multi_array<T,2> AA; //stocke les valeurs des coefficients non nuls par ligne
	boost::multi_array<int,2> JA; //contient les numéros de colonne des elements non nuls
	int dim;
	int nmax; //nombre maximum de zeros
	
	public:
	//constructeur
	MEI(int dim1);
	//methode 
	void printAA();
	void printJA();
	void AjoutElements(T k, int i, int j);
	//produit matrice/vecteur
	void SPMV(const vector <T>& u, vector <T> v,int nmax);
 };
 
 /****************************************************************************
    * Fonction: MEI<T>::MEI()
    * Description: constructeur par parametres
    * Paramètres: int dim1, dimension de la matrice
    * Retour: aucun
    ****************************************************************************/
    template <typename T>
    MEI<T>::MEI(int dim1)
   {
	   //par defaut la matrice est une matrice unite
	   dim=dim1;
	   AA.resize(boost::extents[dim][dim-1]);
	   JA.resize(boost::extents[dim][dim-1]);
	   for(int i=0;i<dim;i++)
	   {
		   AA[i][0]=1;
		   JA[i][0]=i;
		   for(int j=1;j<dim-1;j++)
		   {
			   AA[i][j]=0;
			   JA[i][j]=i; 
		   }
	   }
   }
 
    /****************************************************************************
    * Fonction: MEI<T>::printAA()
    * Description: affiche les indices des valeur non nuls de la matrice
    * Paramètres: aucun
    * Retour: aucun
    ****************************************************************************/
    template <typename T>
    void MEI<T>::printAA()
       {
			for(int i=0; i<AA.shape()[0]; i++)
			{
				for (int j=0; j<AA.shape()[1]; j++)
				{
					cout<<AA[i][j]<<" ";
				}
			
				cout <<" " << endl;
			}
		}

    /****************************************************************************
    * Fonction: MCSR<T>::printJA()
    * Description: affiche les indices des valeur non nuls de la matrice
    * Paramètres: aucun
    * Retour: aucun
    ****************************************************************************/
    
    template <typename T>
    void MEI<T>::printJA()
    {
		for(int i=0; i<JA.shape()[0]; i++)
		{
			for (int j=0; j<JA.shape()[1]; j++)
			{
				cout<<JA[i][j]<<" ";
			}
			
			cout <<" " << endl;
		}
	}
    /****************************************************************************
    * Fonction: MCSR<T>::AjoutElements()
    * Description: Constructeur par paramètres
    * Paramètres: - T k : valeur a ajouter dans le tableau Values
    *             - int nb_lignes: numero de la ligne correspondante
    *             - int nb-colonnes: numero de la colonne correspondante
    *
    * Retour: aucun
    ****************************************************************************/
    template <typename T>
    void MEI<T>::AjoutElements(T k, int i, int j)
    {
		
		int compteur=0;
		int l=0;
		
		while(AA[i][l]!=(T)0 && l<AA.shape()[1])
		{
			cout<<"AA["<<i<<"]["<<l<<"]="<<AA[i][l]<<endl;
			l++;
		}
		cout<<"je suis sorti de la boucle while"<<endl;
		AA[i-1][l]=k;
		cout<<"j'ai fais mon affectation sur"<< "AA["<<i<<"]["<<l<<"]="<<AA[i][l]<<endl;
		for(int k=l;k<dim-1;k++)
		   {
			   JA[i-1][k]=j; 
		   }
		
		cout<<"j'ai fais mon affectation sur"<< "JA["<<i<<"]["<<l<<"]="<<JA[i][l]<<endl;
		
		//on regarde si le nombre max de zeros a diminuer
		cout<<"AA.shape()[0]="<<AA.shape()[0]<<endl;
		for(int i=0; i<AA.shape()[0]; i++)
		{
			if(AA[i][AA.shape()[1]-1] =0)
			{ 
				compteur++;
			}
		}
		//si oui on supprime la derniere colonne des matrices
		if(compteur == 0)
		{
			AA.resize(boost::extents[dim][(AA.shape()[1])-1]);
			JA.resize(boost::extents[dim][(JA.shape()[1])-1]);
		}
			
	}
/****************************************************************************
   * Fonction : SPMV
    * Description :- calcul le produit matrice_creuse/vecteur et enregistre le temps d'execution et les parametre de la matrice dans un fichier
    *                pour un stockage creux du type Ellpack_Itpack, on a 2 tableaux de tailles dim*Nmax, dont un stocke les valeurs des coefficients non nuls par ligne
    *                et un tableau qui contient les numéros de colonne des elements non nuls
    *              - T *u, le vecteur multiplie
    *              - T *v, le vecteur resultat
    * 			   - int dim la dimension de la matrice
    *              - Nmax = max(Nmax[i]) avec Nmax(i], le nombre maximum de valeurs non nuls sur la ligne i
    *              - char* forme, la forme de la matrice
    * Retour: aucun
****************************************************************************/    template <typename T>
    void MEI<T>::SPMV(const vector <T>& u, vector <T> v,int nmax)
    {
		string forme="stockage Ellpack Itpack";
		
		//parametres chronometre
		int compteur;
		int f_compteur=1;
		double temps_moy=0.0000; //temps moyen
		
		
		//while(compteur<f_compteur)
		//{//debut chrono
			timer t;
			t.elapsed();
			for(int i=0;i<dim;i++)
			{
				for(int k=0;k<nmax;k++)
				{
					//cout<<"AA["<<i<<"]["<<k<<"]="<<AA[i][k]<<endl;
					//cout<<"u["<<JA[i][k]<<"]="<<u[JA[i][k]]<<endl;
					v[i]=v[i]+AA[i][k]*u[JA[i][k]];
					//cout<<"v["<<i<<"]="<<v[i]<<endl;
				}
				//cout<<"pour mei : v["<<i<<"]="<<v[i]<<endl;
				//fin chrono
				temps_moy=temps_moy+t.elapsed();
				//compteur++;
			 }
				
			temps_moy = temps_moy/((double)f_compteur);
				
			// ouverture fichier en ecriture seule
			ofstream fichier("creuse_CPP.csv", ios::out | ios::app);
			if(fichier)
			{
				fichier << dim << ";" << forme << ";" << temps_moy << endl;
				fichier.close();
			}			
    }
#endif
